--- /dev/null
+# Getting Started with GTK {#gtk-getting-started}
+
+GTK is a [widget toolkit](http://en.wikipedia.org/wiki/Widget_toolkit).
+Each user interface created by GTK consists of widgets. This is implemented
+in C using [GObject](#gobject), an object-oriented framework for C. Widgets
+are organized in a hierarchy. The window widget is the main container.
+The user interface is then built by adding buttons, drop-down menus, input
+fields, and other widgets to the window. If you are creating complex user
+interfaces it is recommended to use GtkBuilder and its GTK-specific markup
+description language, instead of assembling the interface manually. You can
+also use a visual user interface editor, like [glade](https://glade.gnome.org/).
+
+GTK is event-driven. The toolkit listens for events such as a click
+on a button, and passes the event to your application.
+
+This chapter contains some tutorial information to get you started with
+GTK programming. It assumes that you have GTK, its dependencies and a C
+compiler installed and ready to use. If you need to build GTK itself first,
+refer to the [Compiling the GTK libraries](#gtk-compiling) section in this
+reference.
+
+## Basics
+
+To begin our introduction to GTK, we'll start with a very simple
+application. This program will create an empty 200 × 200 pixel
+window.
+
+
+
+Create a new file with the following content named `example-0.c`.
+
+``` {.c source=examples/window-default.c }
+#include <gtk/gtk.h>
+
+static void
+activate (GtkApplication* app,
+ gpointer user_data)
+{
+ GtkWidget *window;
+
+ window = gtk_application_window_new (app);
+ gtk_window_set_title (GTK_WINDOW (window), "Window");
+ gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
+ gtk_widget_show (window);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GtkApplication *app;
+ int status;
+
+ app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
+ g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
+ status = g_application_run (G_APPLICATION (app), argc, argv);
+ g_object_unref (app);
+
+ return status;
+}
+```
+
+You can compile the program above with GCC using:
+
+```
+gcc `pkg-config --cflags gtk4` -o example-0 example-0.c `pkg-config --libs gtk4`
+```
+
+For more information on how to compile a GTK application, please
+refer to the [Compiling GTK Applications](#gtk-compiling)
+section in this reference.
+
+All GTK applications will, of course, include `gtk/gtk.h`, which declares
+functions, types and macros required by GTK applications.
+
+Even if GTK installs multiple header files, only the top-level `gtk/gtk.h`
+header can be directly included by third-party code. The compiler will abort
+with an error if any othe header is directly included.
+
+In a GTK application, the purpose of the main() function is to create a
+GtkApplication object and run it. In this example a GtkApplication pointer
+named `app` is declared and then initialized using gtk_application_new().
+
+When creating a GtkApplication, you need to pick an application identifier
+(a name) and pass it to gtk_application_new() as parameter. For this example
+`org.gtk.example` is used. For choosing an identifier for your application, see
+[this guide](https://wiki.gnome.org/HowDoI/ChooseApplicationID). Lastly,
+gtk_application_new() takes GApplicationFlags as input for your application,
+if your application would have special needs.
+
+Next the [activate signal](https://wiki.gnome.org/HowDoI/GtkApplication) is
+connected to the activate() function above the main() function. The `activate`
+signal will be emitted when your application is launched with g_application_run()
+on the line below. The g_application_run() call also takes as arguments the
+command line arguments (the `argc` count and the `argv` string array).
+Your application can override the command line handling, e.g. to open
+files passed on the commandline.
+
+Within g_application_run() the activate signal is sent and we then proceed
+into the activate() function of the application. This is where we construct
+our GTK window, so that a window is shown when the application is launched.
+The call to gtk_application_window_new() will create a new GtkWindow and
+store it inside the `window` pointer. The window will have a frame, a title
+bar, and window controls depending on the platform.
+
+A window title is set using gtk_window_set_title(). This function takes a
+GtkWindow* pointer and a string as input. As our `window` pointer is a
+GtkWidget pointer, we need to cast it to GtkWindow*. But instead of casting
+`window` via `(GtkWindow*)`, `window` can be cast using the macro
+`GTK_WINDOW()`. `GTK_WINDOW()` will check if the pointer is an instance of
+the GtkWindow class, before casting, and emit a warning if the check fails.
+More information about this convention can be found
+[here](https://developer.gnome.org/gobject/stable/gtype-conventions.html).
+
+Finally the window size is set using gtk_window_set_default_size()
+and the window is then shown by GTK via gtk_widget_show().
+
+When you close the window, by for example pressing the X, the g_application_run()
+call returns with a number which is saved inside an integer variable named
+`status`. Afterwards, the GtkApplication object is freed from memory with
+g_object_unref(). Finally the status integer is returned and the application
+exits.
+
+While the program is running, GTK is receiving _events_. These are typically
+input events caused by the user interacting with your program, but also things
+like messages from the window manager or other applications. GTK processes
+these and as a result, _signals_ may be emitted on your widgets. Connecting
+handlers for these signals is how you normally make your program do something
+in response to user input.
+
+The following example is slightly more complex, and tries to
+showcase some of the capabilities of GTK.
+
+## Hello, World
+
+In the long tradition of programming languages and libraries,
+this example is called *Hello, World*.
+
+
+
+### Hello World in C {#gtk-getting-started-hello-world}
+
+Create a new file with the following content named `example-1.c`.
+
+``` {.c source=examples/hello-world.c }
+#include <gtk/gtk.h>
+
+static void
+print_hello (GtkWidget *widget,
+ gpointer data)
+{
+ g_print ("Hello World\n");
+}
+
+static void
+activate (GtkApplication *app,
+ gpointer user_data)
+{
+ GtkWidget *window;
+ GtkWidget *button;
+ GtkWidget *box;
+
+ window = gtk_application_window_new (app);
+ gtk_window_set_title (GTK_WINDOW (window), "Window");
+ gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
+
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_window_set_child (GTK_WINDOW (window), box);
+
+ button = gtk_button_new_with_label ("Hello World");
+ g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
+ g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_window_destroy), window);
+ gtk_box_append (GTK_BOX (box), button);
+
+ gtk_widget_show (window);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GtkApplication *app;
+ int status;
+
+ app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
+ g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
+ status = g_application_run (G_APPLICATION (app), argc, argv);
+ g_object_unref (app);
+
+ return status;
+}
+
+```
+
+You can compile the program above with GCC using:
+
+```
+gcc `pkg-config --cflags gtk4` -o example-1 example-1.c `pkg-config --libs gtk4`
+```
+
+As seen above, example-1.c builds further upon example-0.c by adding a
+button to our window, with the label "Hello World". Two new GtkWidget
+pointers are declared to accomplish this, `button` and `box`. The box
+variable is created to store a GtkBox, which is GTK's way of controlling
+the size and layout of buttons.
+
+The GtkBox is created with gtk_box_new() which takes a GtkOrientation
+enum as parameter. The buttons which this box will contain can either be layed
+out horizontally or vertically. This does not matter in this particular case,
+as we are dealing with only one button. After initializing box with the newly
+created GtkBox, the code adds the box widget to the window widget using
+gtk_window_set_child().
+
+Next the `button` variable is initialized in similar manner.
+gtk_button_new_with_label() is called which returns a GtkButton to be
+stored in `button`. Afterwards `button` is added to our `box`.
+
+Using g_signal_connect(), the button is connected to a function in our app called
+print_hello(), so that when the button is clicked, GTK will call this function.
+As the print_hello() function does not use any data as input, NULL is passed
+to it. print_hello() calls g_print() with the string "Hello World" which will
+print Hello World in a terminal if the GTK application was started from one.
+
+After connecting print_hello(), another signal is connected to the "clicked"
+state of the button using g_signal_connect_swapped(). This functions is similar
+to a g_signal_connect() with the difference lying in how the callback function
+is treated. g_signal_connect_swapped() allows you to specify what the callback
+function should take as parameter by letting you pass it as data. In this case
+the function being called back is gtk_window_destroy() and the `window` pointer
+is passed to it. This has the effect that when the button is clicked, the whole
+GTK window is destroyed. In contrast if a normal g_signal_connect() were used
+to connect the "clicked" signal with gtk_window_destroy(), then the function
+would be called on `button` (which would not go well, since the function expects
+a GtkWindow as argument).
+
+More information about creating buttons can be found
+[here](https://wiki.gnome.org/HowDoI/Buttons).
+
+The rest of the code in `example-1.c` is identical to `example-0.c`. The next
+section will elaborate further on how to add several GtkWidgets to your GTK
+application.
+
+## Packing
+
+When creating an application, you'll want to put more than one widget inside
+a window. When you do so, it becomes important to control how each widget is
+positioned and sized. This is where packing comes in.
+
+GTK comes with a large variety of _layout containers_ whose purpose it
+is to control the layout of the child widgets that are added to them.
+See [Layout containers](#LayoutContainers) for an overview.
+
+The following example shows how the GtkGrid container lets you
+arrange several buttons:
+
+
+
+### Packing buttons {#gtk-getting-started-grid-packing}
+
+Create a new file with the following content named `example-2.c`.
+
+``` {.c source=examples/grid-packing.c }
+#include <gtk/gtk.h>
+
+static void
+print_hello (GtkWidget *widget,
+ gpointer data)
+{
+ g_print ("Hello World\n");
+}
+
+static void
+activate (GtkApplication *app,
+ gpointer user_data)
+{
+ GtkWidget *window;
+ GtkWidget *grid;
+ GtkWidget *button;
+
+ /* create a new window, and set its title */
+ window = gtk_application_window_new (app);
+ gtk_window_set_title (GTK_WINDOW (window), "Window");
+
+ /* Here we construct the container that is going pack our buttons */
+ grid = gtk_grid_new ();
+
+ /* Pack the container in the window */
+ gtk_window_set_child (GTK_WINDOW (window), grid);
+
+ button = gtk_button_new_with_label ("Button 1");
+ g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
+
+ /* Place the first button in the grid cell (0, 0), and make it fill
+ * just 1 cell horizontally and vertically (ie no spanning)
+ */
+ gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1);
+
+ button = gtk_button_new_with_label ("Button 2");
+ g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
+
+ /* Place the second button in the grid cell (1, 0), and make it fill
+ * just 1 cell horizontally and vertically (ie no spanning)
+ */
+ gtk_grid_attach (GTK_GRID (grid), button, 1, 0, 1, 1);
+
+ button = gtk_button_new_with_label ("Quit");
+ g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_window_destroy), window);
+
+ /* Place the Quit button in the grid cell (0, 1), and make it
+ * span 2 columns.
+ */
+ gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 2, 1);
+
+ gtk_widget_show (window);
+
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GtkApplication *app;
+ int status;
+
+ app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
+ g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
+ status = g_application_run (G_APPLICATION (app), argc, argv);
+ g_object_unref (app);
+
+ return status;
+}
+```
+
+You can compile the program above with GCC using:
+
+```
+gcc `pkg-config --cflags gtk4` -o example-2 example-2.c `pkg-config --libs gtk4`
+```
+
+## Custom Drawing
+
+Many widgets, like buttons, do all their drawing themselves. You just tell
+them the label you want to see, and they figure out what font to use, draw
+the button outline and focus rectangle, etc. Sometimes, it is necessary to
+do some custom drawing. In that case, a GtkDrawingArea might be the right
+widget to use. It offers a canvas on which you can draw by connecting to
+the ::draw signal.
+
+The contents of a widget often need to be partially or fully redrawn,
+e.g. when another window is moved and uncovers part of the widget, or
+when the window containing it is resized. It is also possible to explicitly
+cause part or all of the widget to be redrawn, by calling
+gtk_widget_queue_draw() or its variants. GTK takes care of most of the
+details by providing a ready-to-use cairo context to the ::draw signal
+handler.
+
+The following example shows a ::draw signal handler. It is a bit more
+complicated than the previous examples, since it also demonstrates
+input event handling by means of event controllers.
+
+
+
+### Drawing in response to input {#gtk-getting-started-drawing}
+
+Create a new file with the following content named `example-4.c`.
+
+``` {.c source=examples/drawing.c }
+#include <gtk/gtk.h>
+
+/* Surface to store current scribbles */
+static cairo_surface_t *surface = NULL;
+
+static void
+clear_surface (void)
+{
+ cairo_t *cr;
+
+ cr = cairo_create (surface);
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+}
+
+/* Create a new surface of the appropriate size to store our scribbles */
+static void
+resize_cb (GtkWidget *widget,
+ int width,
+ int height,
+ gpointer data)
+{
+ if (surface)
+ {
+ cairo_surface_destroy (surface);
+ surface = NULL;
+ }
+
+ if (gtk_native_get_surface (gtk_widget_get_native (widget)))
+ {
+ surface = gdk_surface_create_similar_surface (gtk_native_get_surface (gtk_widget_get_native (widget)),
+ CAIRO_CONTENT_COLOR,
+ gtk_widget_get_width (widget),
+ gtk_widget_get_height (widget));
+
+ /* Initialize the surface to white */
+ clear_surface ();
+ }
+}
+
+/* Redraw the screen from the surface. Note that the draw
+ * callback receives a ready-to-be-used cairo_t that is already
+ * clipped to only draw the exposed areas of the widget
+ */
+static void
+draw_cb (GtkDrawingArea *drawing_area,
+ cairo_t *cr,
+ int width,
+ int height,
+ gpointer data)
+{
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+}
+
+/* Draw a rectangle on the surface at the given position */
+static void
+draw_brush (GtkWidget *widget,
+ gdouble x,
+ gdouble y)
+{
+ cairo_t *cr;
+
+ /* Paint to the surface, where we store our state */
+ cr = cairo_create (surface);
+
+ cairo_rectangle (cr, x - 3, y - 3, 6, 6);
+ cairo_fill (cr);
+
+ cairo_destroy (cr);
+
+ /* Now invalidate the drawing area. */
+ gtk_widget_queue_draw (widget);
+}
+
+static double start_x;
+static double start_y;
+
+static void
+drag_begin (GtkGestureDrag *gesture,
+ double x,
+ double y,
+ GtkWidget *area)
+{
+ start_x = x;
+ start_y = y;
+
+ draw_brush (area, x, y);
+}
+
+static void
+drag_update (GtkGestureDrag *gesture,
+ double x,
+ double y,
+ GtkWidget *area)
+{
+ draw_brush (area, start_x + x, start_y + y);
+}
+
+static void
+drag_end (GtkGestureDrag *gesture,
+ double x,
+ double y,
+ GtkWidget *area)
+{
+ draw_brush (area, start_x + x, start_y + y);
+}
+
+static void
+pressed (GtkGestureClick *gesture,
+ int n_press,
+ double x,
+ double y,
+ GtkWidget *area)
+{
+ clear_surface ();
+ gtk_widget_queue_draw (area);
+}
+
+static void
+close_window (void)
+{
+ if (surface)
+ cairo_surface_destroy (surface);
+}
+
+static void
+activate (GtkApplication *app,
+ gpointer user_data)
+{
+ GtkWidget *window;
+ GtkWidget *frame;
+ GtkWidget *drawing_area;
+ GtkGesture *drag;
+ GtkGesture *press;
+
+ window = gtk_application_window_new (app);
+ gtk_window_set_title (GTK_WINDOW (window), "Drawing Area");
+
+ g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
+
+ frame = gtk_frame_new (NULL);
+ gtk_window_set_child (GTK_WINDOW (window), frame);
+
+ drawing_area = gtk_drawing_area_new ();
+ /* set a minimum size */
+ gtk_widget_set_size_request (drawing_area, 100, 100);
+
+ gtk_frame_set_child (GTK_FRAME (frame), drawing_area);
+
+ gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (drawing_area), draw_cb, NULL, NULL);
+
+ g_signal_connect_after (drawing_area, "resize", G_CALLBACK (resize_cb), NULL);
+
+ drag = gtk_gesture_drag_new ();
+ gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (drag), GDK_BUTTON_PRIMARY);
+ gtk_widget_add_controller (drawing_area, GTK_EVENT_CONTROLLER (drag));
+ g_signal_connect (drag, "drag-begin", G_CALLBACK (drag_begin), drawing_area);
+ g_signal_connect (drag, "drag-update", G_CALLBACK (drag_update), drawing_area);
+ g_signal_connect (drag, "drag-end", G_CALLBACK (drag_end), drawing_area);
+
+ press = gtk_gesture_click_new ();
+ gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (press), GDK_BUTTON_SECONDARY);
+ gtk_widget_add_controller (drawing_area, GTK_EVENT_CONTROLLER (press));
+
+ g_signal_connect (press, "pressed", G_CALLBACK (pressed), drawing_area);
+
+ gtk_widget_show (window);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GtkApplication *app;
+ int status;
+
+ app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
+ g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
+ status = g_application_run (G_APPLICATION (app), argc, argv);
+ g_object_unref (app);
+
+ return status;
+}
+```
+
+You can compile the program above with GCC using:
+
+```
+gcc `pkg-config --cflags gtk4` -o example-4 example-4.c `pkg-config --libs gtk4`
+```
+
+## Building user interfaces
+
+When constructing a more complicated user interface, with dozens
+or hundreds of widgets, doing all the setup work in C code is
+cumbersome, and making changes becomes next to impossible.
+
+Thankfully, GTK supports the separation of user interface
+layout from your business logic, by using UI descriptions in an
+XML format that can be parsed by the GtkBuilder class.</para>
+
+### Packing buttons with GtkBuilder
+
+Create a new file with the following content named `example-3.c`.
+
+``` {.c source=examples/builder.c }
+#include <gtk/gtk.h>
+#include <glib/gstdio.h>
+
+static void
+print_hello (GtkWidget *widget,
+ gpointer data)
+{
+ g_print ("Hello World\n");
+}
+
+static void
+quit_cb (GtkWidget *widget, gpointer data)
+{
+ gboolean *done = data;
+
+ *done = TRUE;
+
+ g_main_context_wakeup (NULL);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ GtkBuilder *builder;
+ GObject *window;
+ GObject *button;
+ gboolean done = FALSE;
+
+#ifdef GTK_SRCDIR
+ g_chdir (GTK_SRCDIR);
+#endif
+
+ gtk_init ();
+
+ /* Construct a GtkBuilder instance and load our UI description */
+ builder = gtk_builder_new ();
+ gtk_builder_add_from_file (builder, "builder.ui", NULL);
+
+ /* Connect signal handlers to the constructed widgets. */
+ window = gtk_builder_get_object (builder, "window");
+ g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
+
+ button = gtk_builder_get_object (builder, "button1");
+ g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
+
+ button = gtk_builder_get_object (builder, "button2");
+ g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
+
+ button = gtk_builder_get_object (builder, "quit");
+ g_signal_connect (button, "clicked", G_CALLBACK (quit_cb), &done);
+
+ gtk_widget_show (GTK_WIDGET (window));
+
+ while (!done)
+ g_main_context_iteration (NULL, TRUE);
+
+ return 0;
+}
+```
+
+Create a new file with the following content named `builder.ui`.
+
+``` {.xml source=examples/builder.ui }
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <object id="window" class="GtkWindow">
+ <property name="title">Grid</property>
+ <child>
+ <object id="grid" class="GtkGrid">
+ <child>
+ <object id="button1" class="GtkButton">
+ <property name="label">Button 1</property>
+ <layout>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </layout>
+ </object>
+ </child>
+ <child>
+ <object id="button2" class="GtkButton">
+ <property name="label">Button 2</property>
+ <layout>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </layout>
+ </object>
+ </child>
+ <child>
+ <object id="quit" class="GtkButton">
+ <property name="label">Quit</property>
+ <layout>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ <property name="column-span">2</property>
+ </layout>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
+```
+
+You can compile the program above with GCC using:
+
+```
+gcc `pkg-config --cflags gtk4` -o example-3 example-3.c `pkg-config --libs gtk4`
+```
+
+Note that GtkBuilder can also be used to construct objects that are
+not widgets, such as tree models, adjustments, etc. That is the reason
+the method we use here is called gtk_builder_get_object() and returns
+a GObject* instead of a GtkWidget*.
+
+Normally, you would pass a full path to gtk_builder_add_from_file() to
+make the execution of your program independent of the current directory.
+A common location to install UI descriptions and similar data is
+`/usr/share/appname`.
+
+It is also possible to embed the UI description in the source code as a
+string and use gtk_builder_add_from_string() to load it. But keeping the
+UI description in a separate file has several advantages: It is then possible
+to make minor adjustments to the UI without recompiling your program, and,
+more importantly, graphical UI editors such as [glade](http://glade.gnome.org)
+can load the file and allow you to create and modify your UI by point-and-click.
+
+## Building applications
+
+An application consists of a number of files:
+
+The binary
+ : This gets installed in `/usr/bin`.
+A desktop file
+ : The desktop file provides important information about the application to
+ the desktop shell, such as its name, icon, D-Bus name, commandline to launch
+ it, etc. It is installed in `/usr/share/applications`.
+An icon
+ : The icon gets installed in `/usr/share/icons/hicolor/48x48/apps`, where it
+will be found regardless of the current theme.
+A settings schema
+ : If the application uses GSettings, it will install its schema in
+ `/usr/share/glib-2.0/schemas`, so that tools like dconf-editor can find it.
+Other resources
+ : Other files, such as GtkBuilder ui files, are best loaded from
+ resources stored in the application binary itself. This eliminates the
+ need for most of the files that would traditionally be installed in
+ an application-specific location in `/usr/share`.
+
+GTK includes application support that is built on top of GApplication. In this
+tutorial we'll build a simple application by starting from scratch, adding more
+and more pieces over time. Along the way, we'll learn about GtkApplication,
+templates, resources, application menus, settings, GtkHeaderBar, GtkStack,
+GtkSearchBar, GtkListBox, and more.
+
+The full, buildable sources for these examples can be found in the `examples/`
+directory of the GTK source distribution, or
+[online](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples in the GTK git
+repository. You can build each example separately by using make with the
+`Makefile.example` file. For more information, see the `README` included in the
+examples directory.
+
+### A trivial application
+
+When using GtkApplication, the main() function can be very simple. We just call
+g_application_run() and give it an instance of our application class.
+
+``` {.c source=examples/application1/main.c }
+#include <gtk/gtk.h>
+
+#include "exampleapp.h"
+
+int
+main (int argc, char *argv[])
+{
+ return g_application_run (G_APPLICATION (example_app_new ()), argc, argv);
+}
+```
+
+All the application logic is in the application class, which is a subclass of
+GtkApplication. Our example does not yet have any interesting functionality.
+All it does is open a window when it is activated without arguments, and open
+the files it is given, if it is started with arguments.
+
+To handle these two cases, we override the activate() vfunc, which gets called
+when the application is launched without commandline arguments, and the open()
+vfunc, which gets called when the application is launched with commandline
+arguments.
+
+To learn more about GApplication entry points, consult the GIO
+[documentation](https://developer.gnome.org/gio/2.36/GApplication.html#GApplication.description).
+
+``` {.c source=examples/application1/exampleapp.c }
+#include <gtk/gtk.h>
+
+#include "exampleapp.h"
+#include "exampleappwin.h"
+
+struct _ExampleApp
+{
+ GtkApplication parent;
+};
+
+G_DEFINE_TYPE(ExampleApp, example_app, GTK_TYPE_APPLICATION);
+
+static void
+example_app_init (ExampleApp *app)
+{
+}
+
+static void
+example_app_activate (GApplication *app)
+{
+ ExampleAppWindow *win;
+
+ win = example_app_window_new (EXAMPLE_APP (app));
+ gtk_window_present (GTK_WINDOW (win));
+}
+
+static void
+example_app_open (GApplication *app,
+ GFile **files,
+ gint n_files,
+ const gchar *hint)
+{
+ GList *windows;
+ ExampleAppWindow *win;
+ int i;
+
+ windows = gtk_application_get_windows (GTK_APPLICATION (app));
+ if (windows)
+ win = EXAMPLE_APP_WINDOW (windows->data);
+ else
+ win = example_app_window_new (EXAMPLE_APP (app));
+
+ for (i = 0; i < n_files; i++)
+ example_app_window_open (win, files[i]);
+
+ gtk_window_present (GTK_WINDOW (win));
+}
+
+static void
+example_app_class_init (ExampleAppClass *class)
+{
+ G_APPLICATION_CLASS (class)->activate = example_app_activate;
+ G_APPLICATION_CLASS (class)->open = example_app_open;
+}
+
+ExampleApp *
+example_app_new (void)
+{
+ return g_object_new (EXAMPLE_APP_TYPE,
+ "application-id", "org.gtk.exampleapp",
+ "flags", G_APPLICATION_HANDLES_OPEN,
+ NULL);
+}
+```
+
+Another important class that is part of the application support in GTK is
+GtkApplicationWindow. It is typically subclassed as well. Our subclass does
+not do anything yet, so we will just get an empty window.
+
+``` {.c source=examples/application1/examplewin.c }
+#include <gtk/gtk.h>
+
+#include "exampleapp.h"
+#include "exampleappwin.h"
+
+struct _ExampleAppWindow
+{
+ GtkApplicationWindow parent;
+};
+
+G_DEFINE_TYPE(ExampleAppWindow, example_app_window, GTK_TYPE_APPLICATION_WINDOW);
+
+static void
+example_app_window_init (ExampleAppWindow *app)
+{
+}
+
+static void
+example_app_window_class_init (ExampleAppWindowClass *class)
+{
+}
+
+ExampleAppWindow *
+example_app_window_new (ExampleApp *app)
+{
+ return g_object_new (EXAMPLE_APP_WINDOW_TYPE, "application", app, NULL);
+}
+
+void
+example_app_window_open (ExampleAppWindow *win,
+ GFile *file)
+{
+}
+```
+
+As part of the initial setup of our application, we also
+create an icon and a desktop file.
+
+
+
+``` { source=examples/application1/org.gtk.exampleapp.desktop }
+[Desktop Entry]
+Type=Application
+Name=Example
+Icon=exampleapp
+StartupNotify=true
+Exec=@bindir@/exampleapp
+```
+
+Note that `@bindir@` needs to be replaced with the actual path to the binary
+before this desktop file can be used.
+
+Here is what we've achieved so far:
+
+
+
+This does not look very impressive yet, but our application is already
+presenting itself on the session bus, it has single-instance semantics,
+and it accepts files as commandline arguments.
+
+### Populating the window
+
+In this step, we use a GtkBuilder template to associate a
+GtkBuilder ui file with our application window class.
+
+Our simple ui file gives the window a title, and puts a GtkStack
+widget as the main content.
+
+``` { .xml source=examples/application2/window.ui }
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="ExampleAppWindow" parent="GtkApplicationWindow">
+ <property name="title" translatable="yes">Example Application</property>
+ <property name="default-width">600</property>
+ <property name="default-height">400</property>
+ <child>
+ <object class="GtkBox" id="content_box">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkStack" id="stack"/>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
+```
+
+To make use of this file in our application, we revisit our
+GtkApplicationWindow subclass, and call
+gtk_widget_class_set_template_from_resource() from the class init
+function to set the ui file as template for this class. We also
+add a call to gtk_widget_init_template() in the instance init
+function to instantiate the template for each instance of our
+class.
+
+```
+ ...
+
+static void
+example_app_window_init (ExampleAppWindow *win)
+{
+ gtk_widget_init_template (GTK_WIDGET (win));
+}
+
+static void
+example_app_window_class_init (ExampleAppWindowClass *class)
+{
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
+ "/org/gtk/exampleapp/window.ui");
+}
+
+ ...
+```
+([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application2/exampleappwin.c))
+
+You may have noticed that we used the `_from_resource()` variant of the function
+that sets a template. Now we need to use
+[GLib's resource functionality](https://developer.gnome.org/gio/stable/GResource.html)
+to include the ui file in the binary. This is commonly done by listing all resources
+in a `.gresource.xml` file, such as this:
+
+``` { .xml source=examples/application2/exampleapp.gresource.xml }
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gtk/exampleapp">
+ <file preprocess="xml-stripblanks">window.ui</file>
+ </gresource>
+</gresources>
+```
+
+This file has to be converted into a C source file that will be compiled and linked
+into the application together with the other source files. To do so, we use the
+`glib-compile-resources` utility:
+
+```
+glib-compile-resources exampleapp.gresource.xml --target=resources.c --generate-source
+```
+
+Our application now looks like this:
+
+
+
+### Opening files
+
+In this step, we make our application show the content of all the files
+that it is given on the commandline.
+
+To this end, we add a member to the struct of our application window subclass
+and keep a reference to the GtkStack there. The first member of the struct
+should be the parent type from which the class is derived. Here,
+ExampleAppWindow is derived from GtkApplicationWindow. The
+gtk_widget_class_bind_template_child() function arranges things so that after
+instantiating the template, the `stack` member of the struct will point to the
+widget of the same name from the template.
+
+```
+...
+
+struct _ExampleAppWindow
+{
+ GtkApplicationWindow parent;
+
+ GtkWidget *stack;
+};
+
+G_DEFINE_TYPE (ExampleAppWindow, example_app_window, GTK_TYPE_APPLICATION_WINDOW)
+
+...
+
+static void
+example_app_window_class_init (ExampleAppWindowClass *class)
+{
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
+ "/org/gtk/exampleapp/window.ui");
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, stack);
+}
+
+...
+```
+([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application3/exampleappwin.c))
+
+Now we revisit the example_app_window_open() function that is called for each
+commandline argument, and construct a GtkTextView that we then add as a page
+to the stack:
+
+```
+...
+
+void
+example_app_window_open (ExampleAppWindow *win,
+ GFile *file)
+{
+ char *basename;
+ GtkWidget *scrolled, *view;
+ char *contents;
+ gsize length;
+
+ basename = g_file_get_basename (file);
+
+ scrolled = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_set_hexpand (scrolled, TRUE);
+ gtk_widget_set_vexpand (scrolled, TRUE);
+ view = gtk_text_view_new ();
+ gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
+ gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
+ gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled), view);
+ gtk_stack_add_titled (GTK_STACK (win->stack), scrolled, basename, basename);
+
+ if (g_file_load_contents (file, NULL, &contents, &length, NULL, NULL))
+ {
+ GtkTextBuffer *buffer;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+ gtk_text_buffer_set_text (buffer, contents, length);
+ g_free (contents);
+ }
+
+ g_free (basename);
+}
+
+...
+```
+([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application3/exampleappwin.c))
+
+Lastly, we add a GtkStackSwitcher to the titlebar area in the ui file, and we
+tell it to display information about our stack.
+
+The stack switcher gets all its information it needs to display tabs from
+the stack that it belongs to. Here, we are passing the label to show for
+each file as the last argument to the gtk_stack_add_titled() function.
+
+Our application is beginning to take shape:
+
+
+
+### A menu
+
+The menu is shown at the right side of the headerbar. It is meant to collect
+infrequently used actions that affect the whole application.
+
+Just like the window template, we specify our menu in a ui file, and add it
+as a resource to our binary.
+
+``` {.xml source=examples/application4/gears-menu.ui }
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <menu id="menu">
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Preferences</attribute>
+ <attribute name="action">app.preferences</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Quit</attribute>
+ <attribute name="action">app.quit</attribute>
+ </item>
+ </section>
+ </menu>
+</interface>
+```
+
+To make the menu appear, we have to load the ui file and associate the
+resulting menu model with the menu button that we've added to the headerbar.
+Since menus work by activating GActions, we also have to add a suitable set
+of actions to our application.
+
+Adding the actions is best done in the startup() vfunc, which is guaranteed
+to be called once for each primary application instance:
+
+```
+...
+
+static void
+preferences_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer app)
+{
+}
+
+static void
+quit_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer app)
+{
+ g_application_quit (G_APPLICATION (app));
+}
+
+static GActionEntry app_entries[] =
+{
+ { "preferences", preferences_activated, NULL, NULL, NULL },
+ { "quit", quit_activated, NULL, NULL, NULL }
+};
+
+static void
+example_app_startup (GApplication *app)
+{
+ GtkBuilder *builder;
+ GMenuModel *app_menu;
+ const gchar *quit_accels[2] = { "<Ctrl>Q", NULL };
+
+ G_APPLICATION_CLASS (example_app_parent_class)->startup (app);
+
+ g_action_map_add_action_entries (G_ACTION_MAP (app),
+ app_entries, G_N_ELEMENTS (app_entries),
+ app);
+ gtk_application_set_accels_for_action (GTK_APPLICATION (app),
+ "app.quit",
+ quit_accels);
+}
+
+static void
+example_app_class_init (ExampleAppClass *class)
+{
+ G_APPLICATION_CLASS (class)->startup = example_app_startup;
+ ...
+}
+
+...
+```
+([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application4/exampleapp.c))
+
+Our preferences menu item does not do anything yet, but the Quit menu item
+is fully functional. Note that it can also be activated by the usual Ctrl-Q
+shortcut. The shortcut was added with gtk_application_set_accels_for_action().
+
+The application menu looks like this:
+
+
+
+### A preference dialog
+
+A typical application will have a some preferences that should be remembered
+from one run to the next. Even for our simple example application, we may
+want to change the font that is used for the content.
+
+We are going to use GSettings to store our preferences. GSettings requires
+a schema that describes our settings:
+
+``` {.xml source=examples/application5/org.gtk.exampleapp.gschema.xml }
+<?xml version="1.0" encoding="UTF-8"?>
+<schemalist>
+ <schema path="/org/gtk/exampleapp/" id="org.gtk.exampleapp">
+ <key name="font" type="s">
+ <default>'Monospace 12'</default>
+ <summary>Font</summary>
+ <description>The font to be used for content.</description>
+ </key>
+ <key name="transition" type="s">
+ <choices>
+ <choice value='none'/>
+ <choice value='crossfade'/>
+ <choice value='slide-left-right'/>
+ </choices>
+ <default>'none'</default>
+ <summary>Transition</summary>
+ <description>The transition to use when switching tabs.</description>
+ </key>
+ </schema>
+</schemalist>
+```
+
+Before we can make use of this schema in our application, we need to compile
+it into the binary form that GSettings expects. GIO provides
+[macros](https://developer.gnome.org/gio/2.36/ch31s06.html) to do this in
+autotools-based projects.
+
+Next, we need to connect our settings to the widgets that they are supposed
+to control. One convenient way to do this is to use GSettings bind
+functionality to bind settings keys to object properties, as we do here
+for the transition setting.
+
+```
+...
+
+static void
+example_app_window_init (ExampleAppWindow *win)
+{
+ gtk_widget_init_template (GTK_WIDGET (win));
+ win->settings = g_settings_new ("org.gtk.exampleapp");
+
+ g_settings_bind (win->settings, "transition",
+ win->stack, "transition-type",
+ G_SETTINGS_BIND_DEFAULT);
+}
+
+...
+```
+([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application5/exampleappwin.c))
+
+The code to connect the font setting is a little more involved, since there
+is no simple object property that it corresponds to, so we are not going to
+go into that here.
+
+At this point, the application will already react if you change one of the
+settings, e.g. using the gsettings commandline tool. Of course, we expect
+the application to provide a preference dialog for these. So lets do that
+now. Our preference dialog will be a subclass of GtkDialog, and we'll use
+the same techniques that we've already seen: templates, private structs,
+settings bindings.
+
+Lets start with the template.
+
+``` {.xml source=examples/application6/prefs.ui }
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="ExampleAppPrefs" parent="GtkDialog">
+ <property name="title" translatable="yes">Preferences</property>
+ <property name="resizable">0</property>
+ <property name="modal">1</property>
+ <child internal-child="content_area">
+ <object class="GtkBox" id="content_area">
+ <child>
+ <object class="GtkGrid" id="grid">
+ <property name="margin-start">12</property>
+ <property name="margin-end">12</property>
+ <property name="margin-top">12</property>
+ <property name="margin-bottom">12</property>
+ <property name="row-spacing">12</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="fontlabel">
+ <property name="label">_Font:</property>
+ <property name="use-underline">1</property>
+ <property name="mnemonic-widget">font</property>
+ <property name="xalign">1</property>
+ <layout>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </layout>
+ </object>
+ </child>
+ <child>
+ <object class="GtkFontButton" id="font">
+ <layout>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </layout>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="transitionlabel">
+ <property name="label">_Transition:</property>
+ <property name="use-underline">1</property>
+ <property name="mnemonic-widget">transition</property>
+ <property name="xalign">1</property>
+ <layout>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </layout>
+ </object>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="transition">
+ <items>
+ <item translatable="yes" id="none">None</item>
+ <item translatable="yes" id="crossfade">Fade</item>
+ <item translatable="yes" id="slide-left-right">Slide</item>
+ </items>
+ <layout>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </layout>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
+```
+
+Next comes the dialog subclass.
+
+``` {.c source=examples/application6/exampleappprefs.c }
+#include <gtk/gtk.h>
+
+#include "exampleapp.h"
+#include "exampleappwin.h"
+#include "exampleappprefs.h"
+
+struct _ExampleAppPrefs
+{
+ GtkDialog parent;
+
+ GSettings *settings;
+ GtkWidget *font;
+ GtkWidget *transition;
+};
+
+G_DEFINE_TYPE (ExampleAppPrefs, example_app_prefs, GTK_TYPE_DIALOG)
+
+static void
+example_app_prefs_init (ExampleAppPrefs *prefs)
+{
+ gtk_widget_init_template (GTK_WIDGET (prefs));
+ prefs->settings = g_settings_new ("org.gtk.exampleapp");
+
+ g_settings_bind (prefs->settings, "font",
+ prefs->font, "font",
+ G_SETTINGS_BIND_DEFAULT);
+ g_settings_bind (prefs->settings, "transition",
+ prefs->transition, "active-id",
+ G_SETTINGS_BIND_DEFAULT);
+}
+
+static void
+example_app_prefs_dispose (GObject *object)
+{
+ ExampleAppPrefs *prefs;
+
+ prefs = EXAMPLE_APP_PREFS (object);
+
+ g_clear_object (&prefs->settings);
+
+ G_OBJECT_CLASS (example_app_prefs_parent_class)->dispose (object);
+}
+
+static void
+example_app_prefs_class_init (ExampleAppPrefsClass *class)
+{
+ G_OBJECT_CLASS (class)->dispose = example_app_prefs_dispose;
+
+ gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
+ "/org/gtk/exampleapp/prefs.ui");
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppPrefs, font);
+ gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppPrefs, transition);
+}
+
+ExampleAppPrefs *
+example_app_prefs_new (ExampleAppWindow *win)
+{
+ return g_object_new (EXAMPLE_APP_PREFS_TYPE, "transient-for", win, "use-header-bar", TRUE, NULL);
+}
+```
+
+Now we revisit the `preferences_activated()` function in our application
+class, and make it open a new preference dialog.
+
+```
+...
+
+static void
+preferences_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer app)
+{
+ ExampleAppPrefs *prefs;
+ GtkWindow *win;
+
+ win = gtk_application_get_active_window (GTK_APPLICATION (app));
+ prefs = example_app_prefs_new (EXAMPLE_APP_WINDOW (win));
+ gtk_window_present (GTK_WINDOW (prefs));
+}
+
+...
+```
+([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application6/exampleapp.c))
+
+After all this work, our application can now show a preference dialog
+like this:
+
+
+
+### Adding a search bar
+
+We continue to flesh out the functionality of our application. For now, we
+add search. GTK supports this with GtkSearchEntry and GtkSearchBar. The
+search bar is a widget that can slide in from the top to present a search
+entry.
+
+We add a toggle button to the header bar, which can be used to slide out
+the search bar below the header bar.
+
+``` {.xml source=examples/application7/window.ui }
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="ExampleAppWindow" parent="GtkApplicationWindow">
+ <property name="title" translatable="yes">Example Application</property>
+ <property name="default-width">600</property>
+ <property name="default-height">400</property>
+ <child type="titlebar">
+ <object class="GtkHeaderBar" id="header">
+ <property name="show-title-buttons">1</property>
+ <child type="title">
+ <object class="GtkStackSwitcher" id="tabs">
+ <property name="stack">stack</property>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkMenuButton" id="gears">
+ <property name="direction">none</property>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkToggleButton" id="search">
+ <property name="sensitive">0</property>
+ <property name="icon-name">edit-find-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="content_box">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkSearchBar" id="searchbar">
+ <child>
+ <object class="GtkSearchEntry" id="searchentry">
+ <signal name="search-changed" handler="search_text_changed"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="stack">
+ <signal name="notify::visible-child" handler="visible_child_changed"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
+```
+
+Implementing the search needs quite a few code changes that we are not
+going to completely go over here. The central piece of the search
+implementation is a signal handler that listens for text changes in
+the search entry.
+
+```
+...
+
+static void
+search_text_changed (GtkEntry *entry,
+ ExampleAppWindow *win)
+{
+ const gchar *text;
+ GtkWidget *tab;
+ GtkWidget *view;
+ GtkTextBuffer *buffer;
+ GtkTextIter start, match_start, match_end;
+
+ text = gtk_editable_get_text (GTK_EDITABLE (entry));
+
+ if (text[0] == '\0')
+ return;
+
+ tab = gtk_stack_get_visible_child (GTK_STACK (win->stack));
+ view = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (tab));
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ /* Very simple-minded search implementation */
+ gtk_text_buffer_get_start_iter (buffer, &start);
+ if (gtk_text_iter_forward_search (&start, text, GTK_TEXT_SEARCH_CASE_INSENSITIVE,
+ &match_start, &match_end, NULL))
+ {
+ gtk_text_buffer_select_range (buffer, &match_start, &match_end);
+ gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (view), &match_start,
+ 0.0, FALSE, 0.0, 0.0);
+ }
+}
+
+static void
+example_app_window_init (ExampleAppWindow *win)
+{
+
+...
+
+ gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), search_text_changed);
+
+...
+
+}
+
+...
+```
+([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application7/exampleappwin.c))
+
+With the search bar, our application now looks like this:
+
+
+
+### Adding a side bar
+
+As another piece of functionality, we are adding a sidebar, which demonstrates
+GtkMenuButton, GtkRevealer and GtkListBox.
+
+``` {.xml source=examples/application8/window.ui }
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="ExampleAppWindow" parent="GtkApplicationWindow">
+ <property name="title" translatable="yes">Example Application</property>
+ <property name="default-width">600</property>
+ <property name="default-height">400</property>
+ <child type="titlebar">
+ <object class="GtkHeaderBar" id="header">
+ <property name="show-title-buttons">1</property>
+ <child type="title">
+ <object class="GtkStackSwitcher" id="tabs">
+ <property name="stack">stack</property>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkToggleButton" id="search">
+ <property name="sensitive">0</property>
+ <property name="icon-name">edit-find-symbolic</property>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkMenuButton" id="gears">
+ <property name="direction">none</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="content_box">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkSearchBar" id="searchbar">
+ <child>
+ <object class="GtkSearchEntry" id="searchentry">
+ <signal name="search-changed" handler="search_text_changed"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="hbox">
+ <child>
+ <object class="GtkRevealer" id="sidebar">
+ <property name="transition-type">slide-right</property>
+ <child>
+ <object class="GtkScrolledWindow" id="sidebar-sw">
+ <property name="hscrollbar-policy">never</property>
+ <child>
+ <object class="GtkListBox" id="words">
+ <property name="selection-mode">none</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="stack">
+ <signal name="notify::visible-child" handler="visible_child_changed"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
+```
+
+The code to populate the sidebar with buttons for the words found in each
+file is a little too involved to go into here. But we'll look at the code
+to add a checkbutton for the new feature to the menu.
+
+``` {.xml source=examples/application8/gears-menu.ui }
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <menu id="menu">
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Words</attribute>
+ <attribute name="action">win.show-words</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Preferences</attribute>
+ <attribute name="action">app.preferences</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Quit</attribute>
+ <attribute name="action">app.quit</attribute>
+ </item>
+ </section>
+ </menu>
+</interface>
+```
+
+To connect the menuitem to the show-words setting, we use
+a GAction corresponding to the given GSettings key.
+
+```
+...
+
+static void
+example_app_window_init (ExampleAppWindow *win)
+{
+
+...
+
+ builder = gtk_builder_new_from_resource ("/org/gtk/exampleapp/gears-menu.ui");
+ menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu"));
+ gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (priv->gears), menu);
+ g_object_unref (builder);
+
+ action = g_settings_create_action (priv->settings, "show-words");
+ g_action_map_add_action (G_ACTION_MAP (win), action);
+ g_object_unref (action);
+}
+
+...
+```
+([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application8/exampleappwin.c))
+
+What our application looks like now:
+
+
+
+### Properties
+
+Widgets and other objects have many useful properties.
+
+Here we show some ways to use them in new and flexible ways, by wrapping
+them in actions with GPropertyAction or by binding them with GBinding.
+
+To set this up, we add two labels to the header bar in our window template,
+named `lines_label` and `lines`, and bind them to struct members in the
+private struct, as we've seen a couple of times by now.
+
+We add a new "Lines" menu item to the gears menu, which triggers the
+show-lines action:
+
+``` {.xml source=examples/application9/gears-menu.ui }
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <menu id="menu">
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Words</attribute>
+ <attribute name="action">win.show-words</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Lines</attribute>
+ <attribute name="action">win.show-lines</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Preferences</attribute>
+ <attribute name="action">app.preferences</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">_Quit</attribute>
+ <attribute name="action">app.quit</attribute>
+ </item>
+ </section>
+ </menu>
+</interface>
+```
+
+To make this menu item do something, we create a property action for the
+visible property of the `lines` label, and add it to the actions of the
+window. The effect of this is that the visibility of the label gets toggled
+every time the action is activated.
+
+Since we want both labels to appear and disappear together, we bind
+the visible property of the `lines_label` widget to the same property
+of the `lines` widget.
+
+```
+...
+
+static void
+example_app_window_init (ExampleAppWindow *win)
+{
+ ...
+
+ action = (GAction*) g_property_action_new ("show-lines", win->lines, "visible");
+ g_action_map_add_action (G_ACTION_MAP (win), action);
+ g_object_unref (action);
+
+ g_object_bind_property (win->lines, "visible",
+ win->lines_label, "visible",
+ G_BINDING_DEFAULT);
+}
+
+...
+```
+([full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application9/exampleappwin.c))
+
+We also need a function that counts the lines of the currently active tab,
+and updates the `lines` label. See the [full source](https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application9/exampleappwin.c)
+if you are interested in the details.
+
+This brings our example application to this appearance:
+
+
+++ /dev/null
-<?xml version="1.0"?>
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
-]>
-<chapter id="gtk-getting-started" xmlns:xi="http://www.w3.org/2003/XInclude">
- <title>Getting Started with GTK</title>
-
- <para>GTK is a <ulink url="http://en.wikipedia.org/wiki/Widget_toolkit">
- widget toolkit</ulink>. Each user interface created by
- GTK consists of widgets. This is implemented in C using
- <link linkend="gobject">GObject</link>, an object-oriented framework for C.
- Widgets are organized in a hierarchy. The window widget is the main container.
- The user interface is then built by adding buttons, drop-down menus, input
- fields, and other widgets to the window.
- If you are creating complex user interfaces it is recommended to
- use GtkBuilder and its GTK-specific markup description language, instead of
- assembling the interface manually. You can also use a visual user interface
- editor, like <ulink url="https://glade.gnome.org/">Glade</ulink>.</para>
-
- <para>GTK is event-driven. The toolkit listens for events such as
- a click on a button, and passes the event to your application.</para>
-
- <para>This chapter contains some tutorial information to get you
- started with GTK programming. It assumes that you have GTK, its
- dependencies and a C compiler installed and ready to use. If you
- need to build GTK itself first, refer to the
- <link linkend="gtk-compiling">Compiling the GTK libraries</link>
- section in this reference.</para>
-
- <section>
- <title>Basics</title>
-
- <para>To begin our introduction to GTK, we'll start with a very simple
- application. This program will create an empty 200 × 200 pixel
- window.</para>
-
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="window-default.png" format="PNG"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
-
- <informalexample>
- <para>Create a new file with the following content named <filename>example-0.c.</filename></para>
- <programlisting><xi:include href="@SRC_DIR@/examples/window-default.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>
- You can compile the program above with GCC using:
- <literallayout>
- <literal>gcc `pkg-config --cflags gtk4` -o example-0 example-0.c `pkg-config --libs gtk4`</literal>
- </literallayout>
- </para>
-
- <note><para>For more information on how to compile a GTK application, please
- refer to the <link linkend="gtk-compiling">Compiling GTK Applications</link>
- section in this reference.</para></note>
-
- <para>All GTK applications will, of course, include
- <filename>gtk/gtk.h</filename>, which declares functions, types and
- macros required by GTK applications.</para>
-
- <warning><para>Even if GTK installs multiple header files, only the
- top-level <filename>gtk/gtk.h</filename> header can be directly included
- by third-party code. The compiler will abort with an error if any other
- header is directly included.</para></warning>
-
- <para>In a GTK application, the purpose of the main() function is
- to create a GtkApplication object and run it. In this example a
- GtkApplication pointer named <varname>app</varname> is declared
- and then initialized using gtk_application_new().</para>
-
- <para>When creating a GtkApplication, you need to pick an application
- identifier (a name) and pass it to gtk_application_new() as parameter.
- For this example <varname>org.gtk.example</varname> is used. For
- choosing an identifier for your application, see
- <ulink url="https://wiki.gnome.org/HowDoI/ChooseApplicationID">this guide</ulink>.
- Lastly gtk_application_new() takes GApplicationFlags as input for your
- application, if your application would have special needs.
- </para>
-
- <para>Next the
- <ulink url="https://wiki.gnome.org/HowDoI/GtkApplication">activate signal</ulink>
- is connected to the activate() function above the main() function.
- The <varname>activate</varname> signal will be emitted when your application
- is launched with g_application_run() on the line below. The g_application_run()
- call also takes as arguments the command line arguments (the
- <varname>argc</varname> count and the <varname>argv</varname> string array).
- Your application can override the command line handling, e.g. to open
- files passed on the commandline.
- </para>
-
- <para>Within g_application_run() the activate signal is sent and we then
- proceed into the activate() function of the application. This is where we
- construct our GTK window, so that a window is shown when the application
- is launched. The call to gtk_application_window_new() will create a new
- GtkWindow and store it inside the <varname>window</varname> pointer. The
- window will have a frame, a title bar, and window controls depending on
- the platform.</para>
-
- <para>A window title is set using gtk_window_set_title(). This function
- takes a GtkWindow* pointer and a string as input. As our
- <varname>window</varname> pointer is a GtkWidget pointer, we need to cast
- it to GtkWindow*. But instead of casting <varname>window</varname> via
- <varname>(GtkWindow*)</varname>, <varname>window</varname> can be cast
- using the macro <varname>GTK_WINDOW()</varname>. <varname>GTK_WINDOW()</varname>
- will check if the pointer is an instance of the GtkWindow class, before
- casting, and emit a warning if the check fails. More information about
- this convention can be found
- <ulink url="https://developer.gnome.org/gobject/stable/gtype-conventions.html">
- here</ulink>.</para>
-
- <para>Finally the window size is set using gtk_window_set_default_size()
- and the window is then shown by GTK via gtk_widget_show().</para>
-
- <para>When you close the window, by for example pressing the X, the
- g_application_run() call returns with a number which is saved inside
- an integer variable named <varname>status</varname>. Afterwards, the
- GtkApplication object is freed from memory with g_object_unref().
- Finally the status integer is returned and the application exits.</para>
-
- <para>While the program is running, GTK is receiving
- <firstterm>events</firstterm>. These are typically input events caused by
- the user interacting with your program, but also things like messages from
- the window manager or other applications. GTK processes these and as a
- result, <firstterm>signals</firstterm> may be emitted on your widgets.
- Connecting handlers for these signals is how you normally make your
- program do something in response to user input.</para>
-
- <para>The following example is slightly more complex, and tries to
- showcase some of the capabilities of GTK.</para>
-
- </section>
- <section>
- <title>Hello, World</title>
-
- <para>In the long tradition of programming languages and libraries,
- this example is called <emphasis>Hello, World</emphasis>.</para>
-
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="hello-world.png" format="PNG"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
-
- <example id="gtk-getting-started-hello-world">
- <title>Hello World in GTK</title>
- <para>Create a new file with the following content named example-1.c.</para>
- <programlisting><xi:include href="@SRC_DIR@/examples/hello-world.c" parse="text">
- <xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </example>
-
- <para>
- You can compile the program above with GCC using:
- <literallayout>
- <literal>gcc `pkg-config --cflags gtk4` -o example-1 example-1.c `pkg-config --libs gtk4`</literal>
- </literallayout>
- </para>
-
- <para>As seen above, example-1.c builds further upon example-0.c by adding a
- button to our window, with the label "Hello World". Two new GtkWidget pointers
- are declared to accomplish this, <varname>button</varname> and
- <varname>box</varname>. The box variable is created to store a GtkBox, which
- is GTK's way of controlling the size and layout of buttons.
- </para>
-
- <para>The GtkBox is created with gtk_box_new() which takes a GtkOrientation
- enum as parameter. The buttons which this box will contain can either be layed
- out horizontally or vertically. This does not matter in this particular case,
- as we are dealing with only one button. After initializing box with the newly
- created GtkBox, the code adds the box widget to the window widget using
- gtk_window_set_child().</para>
-
- <para>Next the <varname>button</varname> variable is initialized in similar manner.
- gtk_button_new_with_label() is called which returns a GtkButton to be stored in
- <varname>button</varname>. Afterwards <varname>button</varname> is added to
- our <varname>box</varname>.
- </para>
-
- <para>
- Using g_signal_connect(), the button is connected to a function in our app called
- print_hello(), so that when the button is clicked, GTK will call this function.
- As the print_hello() function does not use any data as input, NULL is passed
- to it. print_hello() calls g_print() with the string "Hello World"
- which will print Hello World in a terminal if the GTK application was started
- from one.</para>
-
- <para>After connecting print_hello(), another signal is connected to the "clicked"
- state of the button using g_signal_connect_swapped(). This functions is similar to
- a g_signal_connect() with the difference lying in how the callback function is
- treated. g_signal_connect_swapped() allows you to specify what the callback
- function should take as parameter by letting you pass it as data. In this case
- the function being called back is gtk_window_destroy() and the <varname>window</varname>
- pointer is passed to it. This has the effect that when the button is clicked,
- the whole GTK window is destroyed. In contrast if a normal g_signal_connect() were used
- to connect the "clicked" signal with gtk_window_destroy(), then the function
- would be called on <varname>button</varname> (which would not go well, since
- the function expects a GtkWindow as argument).
- More information about creating buttons can be found
- <ulink url="https://wiki.gnome.org/HowDoI/Buttons">here</ulink>.
- </para>
-
- <para>The rest of the code in example-1.c is identical to example-0.c. The next
- section will elaborate further on how to add several GtkWidgets to your GTK
- application.</para>
- </section>
-
- <section>
- <title>Packing</title>
-
- <para>When creating an application, you'll want to put more than one widget
- inside a window. When you do so, it becomes important to control how each widget
- is positioned and sized. This is where packing comes in.</para>
-
- <para>GTK comes with a large variety of <firstterm>layout containers</firstterm>
- whose purpose it is to control the layout of the child widgets that are
- added to them. See <xref linkend="LayoutContainers"/> for an overview.</para>
-
- <para>The following example shows how the GtkGrid container lets you
- arrange several buttons:</para>
-
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="grid-packing.png" format="PNG"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
-
- <example id="gtk-getting-started-grid-packing">
- <title>Packing buttons</title>
- <para>Create a new file with the following content named example-2.c.</para>
- <programlisting><xi:include href="@SRC_DIR@/examples/grid-packing.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </example>
- <para>
- You can compile the program above with GCC using:
- <literallayout>
- <literal>gcc `pkg-config --cflags gtk4` -o example-2 example-2.c `pkg-config --libs gtk4`</literal>
- </literallayout>
- </para>
- </section>
-
- <section>
- <title>Custom Drawing</title>
-
- <para>Many widgets, like buttons, do all their drawing themselves. You
- just tell them the label you want to see, and they figure out what font
- to use, draw the button outline and focus rectangle, etc. Sometimes, it
- is necessary to do some custom drawing. In that case, a GtkDrawingArea
- might be the right widget to use. It offers a canvas on which you can
- draw by connecting to the ::draw signal.
- </para>
-
- <para>The contents of a widget often need to be partially or fully redrawn,
- e.g. when another window is moved and uncovers part of the widget, or
- when the window containing it is resized. It is also possible to explicitly
- cause part or all of the widget to be redrawn, by calling
- gtk_widget_queue_draw() or its variants. GTK takes care of most of the
- details by providing a ready-to-use cairo context to the ::draw signal
- handler.</para>
-
- <para>The following example shows a ::draw signal handler. It is a bit
- more complicated than the previous examples, since it also demonstrates
- input event handling by means of event controllers.</para>
-
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="drawing.png" format="PNG"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
-
- <example id="gtk-getting-started-drawing">
- <title>Drawing in response to input</title>
- <para>Create a new file with the following content named example-4.c.</para>
- <programlisting><xi:include href="@SRC_DIR@/examples/drawing.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </example>
- <para>
- You can compile the program above with GCC using:
- <literallayout>
- <literal>gcc `pkg-config --cflags gtk4` -o example-4 example-4.c `pkg-config --libs gtk4`</literal>
- </literallayout>
- </para>
- </section>
-
- <section>
- <title>Building user interfaces</title>
-
- <para>When constructing a more complicated user interface, with dozens
- or hundreds of widgets, doing all the setup work in C code is
- cumbersome, and making changes becomes next to impossible.</para>
-
- <para>Thankfully, GTK supports the separation of user interface
- layout from your business logic, by using UI descriptions in an
- XML format that can be parsed by the GtkBuilder class.</para>
-
- <example>
- <title>Packing buttons with GtkBuilder</title>
- <para>Create a new file with the following content named example-3.c.</para>
- <programlisting><xi:include href="@SRC_DIR@/examples/builder.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- <para>Create a new file with the following content named builder.ui.</para>
- <programlisting><xi:include href="@SRC_DIR@/examples/builder.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </example>
- <para>
- You can compile the program above with GCC using:
- <literallayout>
- <literal>gcc `pkg-config --cflags gtk4` -o example-3 example-3.c `pkg-config --libs gtk4`</literal>
- </literallayout>
- </para>
-
- <para>Note that GtkBuilder can also be used to construct objects
- that are not widgets, such as tree models, adjustments, etc.
- That is the reason the method we use here is called
- gtk_builder_get_object() and returns a GObject* instead of a
- GtkWidget*.</para>
-
- <para>Normally, you would pass a full path to
- gtk_builder_add_from_file() to make the execution of your program
- independent of the current directory. A common location to install
- UI descriptions and similar data is
- <filename>/usr/share/<replaceable>appname</replaceable></filename>.
- </para>
-
- <para>It is also possible to embed the UI description in the source
- code as a string and use gtk_builder_add_from_string() to load it.
- But keeping the UI description in a separate file has several
- advantages: It is then possible to make minor adjustments to the UI
- without recompiling your program, and, more importantly, graphical
- UI editors such as <ulink url="http://glade.gnome.org">glade</ulink>
- can load the file and allow you to create and modify your UI by
- point-and-click.</para>
- </section>
-
- <section>
- <title>Building applications</title>
-
- <para>An application consists of a number of files:
- <variablelist>
- <varlistentry>
- <term>The binary</term>
- <listitem>This gets installed in <filename>/usr/bin</filename>.</listitem>
- </varlistentry>
- <varlistentry>
- <term>A desktop file</term>
- <listitem>The desktop file provides important information about the application to the desktop shell, such as its name, icon, D-Bus name, commandline to launch it, etc. It is installed in <filename>/usr/share/applications</filename>.</listitem>
- </varlistentry>
- <varlistentry>
- <term>An icon</term>
- <listitem>The icon gets installed in <filename>/usr/share/icons/hicolor/48x48/apps</filename>, where it will be found regardless of the current theme.</listitem>
- </varlistentry>
- <varlistentry>
- <term>A settings schema</term>
- <listitem>If the application uses GSettings, it will install its schema
- in <filename>/usr/share/glib-2.0/schemas</filename>, so that tools
- like dconf-editor can find it.</listitem>
- </varlistentry>
- <varlistentry>
- <term>Other resources</term>
- <listitem>Other files, such as GtkBuilder ui files, are best loaded from
- resources stored in the application binary itself. This eliminates the
- need for most of the files that would traditionally be installed in
- an application-specific location in <filename>/usr/share</filename>.</listitem>
- </varlistentry>
- </variablelist>
- </para>
-
- <para>GTK includes application support that is built on top of
- GApplication. In this tutorial we'll build a simple application by
- starting from scratch, adding more and more pieces over time. Along
- the way, we'll learn about GtkApplication, templates, resources,
- application menus, settings, GtkHeaderBar, GtkStack, GtkSearchBar,
- GtkListBox, and more.</para>
-
- <para>The full, buildable sources for these examples can be found in the
- <filename>examples/</filename> directory of the GTK source distribution, or
- <ulink url="https://gitlab.gnome.org/GNOME/gtk/blob/master/examples">online</ulink> in the GTK git repository.
- You can build each example separately by using make with the <filename>Makefile.example</filename>
- file. For more information, see the <filename>README</filename> included in the
- examples directory.</para>
-
- <section>
- <title>A trivial application</title>
-
- <para>When using GtkApplication, the main() function can be very
- simple. We just call g_application_run() and give it an instance
- of our application class.</para>
-
- <informalexample>
- <programlisting><xi:include href="@SRC_DIR@/examples/application1/main.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>All the application logic is in the application class, which
- is a subclass of GtkApplication. Our example does not yet have any
- interesting functionality. All it does is open a window when it is
- activated without arguments, and open the files it is given, if it
- is started with arguments.</para>
-
- <para>To handle these two cases, we override the activate() vfunc,
- which gets called when the application is launched without commandline
- arguments, and the open() vfunc, which gets called when the application
- is launched with commandline arguments.</para>
-
- <para>To learn more about GApplication entry points, consult the
- GIO <ulink url="https://developer.gnome.org/gio/2.36/GApplication.html#GApplication.description">documentation</ulink>.</para>
-
- <informalexample>
- <programlisting><xi:include href="@SRC_DIR@/examples/application1/exampleapp.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>Another important class that is part of the application support
- in GTK is GtkApplicationWindow. It is typically subclassed as well.
- Our subclass does not do anything yet, so we will just get an empty
- window.</para>
-
- <informalexample>
- <programlisting><xi:include href="@SRC_DIR@/examples/application1/exampleappwin.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>As part of the initial setup of our application, we also
- create an icon and a desktop file.</para>
-
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="exampleapp.png" format="PNG"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
-
- <informalexample>
- <programlisting><xi:include href="@SRC_DIR@/examples/application1/org.gtk.exampleapp.desktop" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>Note that <replaceable>@<!-- -->bindir@</replaceable> needs to be replaced
- with the actual path to the binary before this desktop file can be used.</para>
-
- <para>Here is what we've achieved so far:</para>
-
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="getting-started-app1.png" format="PNG"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
-
- <para>This does not look very impressive yet, but our application
- is already presenting itself on the session bus, it has single-instance
- semantics, and it accepts files as commandline arguments.</para>
- </section>
-
- <section>
- <title>Populating the window</title>
-
- <para>In this step, we use a GtkBuilder template to associate a
- GtkBuilder ui file with our application window class.</para>
- <para>Our simple ui file gives the window a title, and puts a GtkStack
- widget as the main content.
- </para>
-
- <informalexample>
- <programlisting><xi:include href="@SRC_DIR@/examples/application2/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>To make use of this file in our application, we revisit
- our GtkApplicationWindow subclass, and call
- gtk_widget_class_set_template_from_resource() from the class init
- function to set the ui file as template for this class. We also
- add a call to gtk_widget_init_template() in the instance init
- function to instantiate the template for each instance of our
- class.</para>
-
- <informalexample>
- <programlisting><![CDATA[
- ...
-
-static void
-example_app_window_init (ExampleAppWindow *win)
-{
- gtk_widget_init_template (GTK_WIDGET (win));
-}
-
-static void
-example_app_window_class_init (ExampleAppWindowClass *class)
-{
- gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
- "/org/gtk/exampleapp/window.ui");
-}
-
- ...
- ]]></programlisting>
- <para>(<ulink url="https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application2/exampleappwin.c">full source</ulink>)</para>
- </informalexample>
-
- <para>You may have noticed that we used the <literal>_from_resource()</literal>
- variant of the function that sets a template. Now we need to use
- <ulink url="https://developer.gnome.org/gio/stable/GResource.html">GLib's resource functionality</ulink>
- to include the ui file in the binary. This is commonly done by listing
- all resources in a .gresource.xml file, such as this:
- </para>
-
- <informalexample>
- <programlisting><xi:include href="@SRC_DIR@/examples/application2/exampleapp.gresource.xml" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>This file has to be converted into a C source file that will be
- compiled and linked into the application together with the other source
- files. To do so, we use the glib-compile-resources utility:</para>
-
- <screen>
- glib-compile-resources exampleapp.gresource.xml --target=resources.c --generate-source
- </screen>
-
- <para>Our application now looks like this:</para>
-
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="getting-started-app2.png" format="PNG"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- </section>
-
- <section>
- <title>Opening files</title>
-
- <para>In this step, we make our application show the content of
- all the files that it is given on the commandline.</para>
-
- <para>To this end, we add a member to the struct of our application
- window subclass and keep a reference to the GtkStack there. The first
- member of the struct should be the parent type from which the class is
- derived. Here, ExampleAppWindow is derived from GtkApplicationWindow.
- The gtk_widget_class_bind_template_child() function arranges things so
- that after instantiating the template, the <varname>stack</varname>
- member of the struct will point to the widget of the same name from
- the template.</para>
-
- <informalexample>
- <programlisting><![CDATA[
-...
-
-struct _ExampleAppWindow
-{
- GtkApplicationWindow parent;
-
- GtkWidget *stack;
-};
-
-G_DEFINE_TYPE (ExampleAppWindow, example_app_window, GTK_TYPE_APPLICATION_WINDOW)
-
-...
-
-static void
-example_app_window_class_init (ExampleAppWindowClass *class)
-{
- gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
- "/org/gtk/exampleapp/window.ui");
- gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, stack);
-}
-
-...
- ]]></programlisting>
- <para>(<ulink url="https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application3/exampleappwin.c">full source</ulink>)</para>
- </informalexample>
-
- <para>Now we revisit the example_app_window_open() function that
- is called for each commandline argument, and construct a GtkTextView
- that we then add as a page to the stack:</para>
-
- <informalexample>
- <programlisting><![CDATA[
-...
-
-void
-example_app_window_open (ExampleAppWindow *win,
- GFile *file)
-{
- char *basename;
- GtkWidget *scrolled, *view;
- char *contents;
- gsize length;
-
- basename = g_file_get_basename (file);
-
- scrolled = gtk_scrolled_window_new (NULL, NULL);
- gtk_widget_set_hexpand (scrolled, TRUE);
- gtk_widget_set_vexpand (scrolled, TRUE);
- view = gtk_text_view_new ();
- gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
- gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
- gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled), view);
- gtk_stack_add_titled (GTK_STACK (win->stack), scrolled, basename, basename);
-
- if (g_file_load_contents (file, NULL, &contents, &length, NULL, NULL))
- {
- GtkTextBuffer *buffer;
-
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
- gtk_text_buffer_set_text (buffer, contents, length);
- g_free (contents);
- }
-
- g_free (basename);
-}
-
-...
- ]]></programlisting>
- <para>(<ulink url="https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application3/exampleappwin.c">full source</ulink>)</para>
- </informalexample>
-
- <para>Lastly, we add a GtkStackSwitcher to the titlebar area
- in the ui file, and we tell it to display information about our
- stack.</para>
-
- <para>The stack switcher gets all its information it needs to
- display tabs from the stack that it belongs to. Here, we are
- passing the label to show for each file as the last argument to
- the gtk_stack_add_titled() function.</para>
-
- <para>Our application is beginning to take shape:</para>
-
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="getting-started-app3.png" format="PNG"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- </section>
-
- <section>
- <title>A menu</title>
-
- <para>The menu is shown at the right side of the headerbar.
- It is meant to collect infrequently used actions that affect
- the whole application.</para>
-
- <para>Just like the window template, we specify our menu
- in a ui file, and add it as a resource to our binary.</para>
-
- <informalexample>
- <programlisting><xi:include href="@SRC_DIR@/examples/application4/gears-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>To make the menu appear, we have to load the ui file and
- associate the resulting menu model with the menu button that we've
- added to the headerbar. Since menus work by activating GActions,
- we also have to add a suitable set of actions to our application.</para>
-
- <para>Adding the actions is best done in the startup() vfunc,
- which is guaranteed to be called once for each primary application
- instance:</para>
- <informalexample>
- <programlisting>
-...
-
-static void
-preferences_activated (GSimpleAction *action,
- GVariant *parameter,
- gpointer app)
-{
-}
-
-static void
-quit_activated (GSimpleAction *action,
- GVariant *parameter,
- gpointer app)
-{
- g_application_quit (G_APPLICATION (app));
-}
-
-static GActionEntry app_entries[] =
-{
- { "preferences", preferences_activated, NULL, NULL, NULL },
- { "quit", quit_activated, NULL, NULL, NULL }
-};
-
-static void
-example_app_startup (GApplication *app)
-{
- GtkBuilder *builder;
- GMenuModel *app_menu;
- const gchar *quit_accels[2] = { "<Ctrl>Q", NULL };
-
- G_APPLICATION_CLASS (example_app_parent_class)->startup (app);
-
- g_action_map_add_action_entries (G_ACTION_MAP (app),
- app_entries, G_N_ELEMENTS (app_entries),
- app);
- gtk_application_set_accels_for_action (GTK_APPLICATION (app),
- "app.quit",
- quit_accels);
-}
-
-static void
-example_app_class_init (ExampleAppClass *class)
-{
- G_APPLICATION_CLASS (class)->startup = example_app_startup;
- ...
-}
-
-...
- </programlisting>
- <para>(<ulink url="https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application4/exampleapp.c">full source</ulink>)</para>
- </informalexample>
-
- <para>Our preferences menu item does not do anything yet,
- but the Quit menu item is fully functional. Note that it
- can also be activated by the usual Ctrl-Q shortcut. The
- shortcut was added with gtk_application_set_accels_for_action().
- </para>
-
- <para>The application menu looks like this:</para>
-
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="getting-started-app4.png" format="PNG"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- </section>
-
- <section>
- <title>A preference dialog</title>
-
- <para>A typical application will have a some preferences that
- should be remembered from one run to the next. Even for our
- simple example application, we may want to change the font
- that is used for the content.</para>
-
- <para>We are going to use GSettings to store our preferences.
- GSettings requires a schema that describes our settings:</para>
-
- <informalexample>
- <programlisting><xi:include href="@SRC_DIR@/examples/application5/org.gtk.exampleapp.gschema.xml" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>Before we can make use of this schema in our application,
- we need to compile it into the binary form that GSettings
- expects. GIO provides <ulink url="https://developer.gnome.org/gio/2.36/ch31s06.html">macros</ulink>
- to do this in autotools-based projects.</para>
-
- <para>Next, we need to connect our settings to the widgets
- that they are supposed to control. One convenient way to do
- this is to use GSettings bind functionality to bind settings
- keys to object properties, as we do here for the transition
- setting.</para>
-
- <informalexample>
- <programlisting><![CDATA[
-...
-
-static void
-example_app_window_init (ExampleAppWindow *win)
-{
- gtk_widget_init_template (GTK_WIDGET (win));
- win->settings = g_settings_new ("org.gtk.exampleapp");
-
- g_settings_bind (win->settings, "transition",
- win->stack, "transition-type",
- G_SETTINGS_BIND_DEFAULT);
-}
-
-...
- ]]></programlisting>
- <para>(<ulink url="https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application5/exampleappwin.c">full source</ulink>)</para>
- </informalexample>
-
- <para>The code to connect the font setting is a little more involved,
- since there is no simple object property that it corresponds to, so
- we are not going to go into that here.</para>
-
- <para>At this point, the application will already react if you
- change one of the settings, e.g. using the gsettings commandline
- tool. Of course, we expect the application to provide a preference
- dialog for these. So lets do that now. Our preference dialog will
- be a subclass of GtkDialog, and we'll use the same techniques that
- we've already seen: templates, private structs, settings
- bindings.</para>
-
- <para>Lets start with the template.</para>
-
- <informalexample>
- <programlisting><xi:include href="@SRC_DIR@/examples/application6/prefs.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>Next comes the dialog subclass.</para>
-
- <informalexample>
- <programlisting><xi:include href="@SRC_DIR@/examples/application6/exampleappprefs.c" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>Now we revisit the <literal>preferences_activated()</literal>
- function in our application class, and make it open a new preference
- dialog.</para>
-
- <informalexample>
- <programlisting><![CDATA[
-...
-
-static void
-preferences_activated (GSimpleAction *action,
- GVariant *parameter,
- gpointer app)
-{
- ExampleAppPrefs *prefs;
- GtkWindow *win;
-
- win = gtk_application_get_active_window (GTK_APPLICATION (app));
- prefs = example_app_prefs_new (EXAMPLE_APP_WINDOW (win));
- gtk_window_present (GTK_WINDOW (prefs));
-}
-
-...
- ]]></programlisting>
- <para>(<ulink url="https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application6/exampleapp.c">full source</ulink>)</para>
- </informalexample>
-
- <para>After all this work, our application can now show
- a preference dialog like this:</para>
-
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="getting-started-app6.png" format="PNG"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- </section>
-
- <section>
- <title>Adding a search bar</title>
-
- <para>We continue to flesh out the functionality of our application.
- For now, we add search. GTK supports this with GtkSearchEntry and
- GtkSearchBar. The search bar is a widget that can slide in from the
- top to present a search entry.</para>
-
- <para>We add a toggle button to the header bar, which can be used
- to slide out the search bar below the header bar.</para>
-
- <informalexample>
- <programlisting><xi:include href="@SRC_DIR@/examples/application7/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>Implementing the search needs quite a few code changes that
- we are not going to completely go over here. The central piece of
- the search implementation is a signal handler that listens for
- text changes in the search entry.</para>
-
- <informalexample>
- <programlisting><![CDATA[
-...
-
-static void
-search_text_changed (GtkEntry *entry,
- ExampleAppWindow *win)
-{
- const gchar *text;
- GtkWidget *tab;
- GtkWidget *view;
- GtkTextBuffer *buffer;
- GtkTextIter start, match_start, match_end;
-
- text = gtk_editable_get_text (GTK_EDITABLE (entry));
-
- if (text[0] == '\0')
- return;
-
- tab = gtk_stack_get_visible_child (GTK_STACK (win->stack));
- view = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (tab));
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
-
- /* Very simple-minded search implementation */
- gtk_text_buffer_get_start_iter (buffer, &start);
- if (gtk_text_iter_forward_search (&start, text, GTK_TEXT_SEARCH_CASE_INSENSITIVE,
- &match_start, &match_end, NULL))
- {
- gtk_text_buffer_select_range (buffer, &match_start, &match_end);
- gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (view), &match_start,
- 0.0, FALSE, 0.0, 0.0);
- }
-}
-
-static void
-example_app_window_init (ExampleAppWindow *win)
-{
-
-...
-
- gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), search_text_changed);
-
-...
-
-}
-
-...
- ]]></programlisting>
- <para>(<ulink url="https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application7/exampleappwin.c">full source</ulink>)</para>
- </informalexample>
-
- <para>With the search bar, our application now looks like this:</para>
-
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="getting-started-app7.png" format="PNG"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- </section>
-
- <section>
- <title>Adding a side bar</title>
-
- <para>As another piece of functionality, we are adding a sidebar,
- which demonstrates GtkMenuButton, GtkRevealer and GtkListBox.</para>
-
- <informalexample>
- <programlisting><xi:include href="@SRC_DIR@/examples/application8/window.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>The code to populate the sidebar with buttons for the words
- found in each file is a little too involved to go into here. But we'll
- look at the code to add a checkbutton for the new feature to the menu.</para>
-
- <informalexample>
- <programlisting><xi:include href="@SRC_DIR@/examples/application8/gears-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>To connect the menuitem to the show-words setting, we use
- a GAction corresponding to the given GSettings key.</para>
-
- <informalexample>
- <programlisting><![CDATA[
-...
-
-static void
-example_app_window_init (ExampleAppWindow *win)
-{
-
-...
-
- builder = gtk_builder_new_from_resource ("/org/gtk/exampleapp/gears-menu.ui");
- menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu"));
- gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (priv->gears), menu);
- g_object_unref (builder);
-
- action = g_settings_create_action (priv->settings, "show-words");
- g_action_map_add_action (G_ACTION_MAP (win), action);
- g_object_unref (action);
-}
-
-...
- ]]></programlisting>
- <para>(<ulink url="https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application8/exampleappwin.c">full source</ulink>)</para>
- </informalexample>
-
- <para>What our application looks like now:</para>
-
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="getting-started-app8.png" format="PNG"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- </section>
- <section>
- <title>Properties</title>
-
- <para>Widgets and other objects have many useful properties.</para>
-
- <para>Here we show some ways to use them in new and flexible ways,
- by wrapping them in actions with GPropertyAction or by binding them
- with GBinding.</para>
-
- <para>To set this up, we add two labels to the header bar in our
- window template, named <varname>lines_label</varname> and
- <varname>lines</varname>, and bind them to struct members in the
- private struct, as we've seen a couple of times by now.</para>
-
- <para>We add a new "Lines" menu item to the gears menu, which
- triggers the show-lines action:</para>
-
- <informalexample>
- <programlisting><xi:include href="@SRC_DIR@/examples/application9/gears-menu.ui" parse="text"><xi:fallback>MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
- </informalexample>
-
- <para>To make this menu item do something, we create a property
- action for the visible property of the <varname>lines</varname> label,
- and add it to the actions of the window. The effect of this is that the
- visibility of the label gets toggled every time the action is activated.
- </para>
-
- <para>Since we want both labels to appear and disappear together, we bind
- the visible property of the <varname>lines_label</varname> widget to the
- same property of the <varname>lines</varname> widget.</para>
-
- <informalexample>
- <programlisting>
-...
-
-static void
-example_app_window_init (ExampleAppWindow *win)
-{
- ...
-
- action = (GAction*) g_property_action_new ("show-lines", win->lines, "visible");
- g_action_map_add_action (G_ACTION_MAP (win), action);
- g_object_unref (action);
-
- g_object_bind_property (win->lines, "visible",
- win->lines_label, "visible",
- G_BINDING_DEFAULT);
-}
-
-...
- </programlisting>
- <para>(<ulink url="https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application9/exampleappwin.c">full source</ulink>)</para>
- </informalexample>
-
- <para>We also need a function that counts the lines of the currently
- active tab, and updates the <varname>lines</varname> label. See the
- <ulink url="https://gitlab.gnome.org/GNOME/gtk/blob/master/examples/application9/exampleappwin.c">full source</ulink>
- if you are interested in the details.</para>
-
- <para>This brings our example application to this appearance:</para>
-
- <informalfigure>
- <mediaobject>
- <imageobject>
- <imagedata fileref="getting-started-app9.png" format="PNG"/>
- </imageobject>
- </mediaobject>
- </informalfigure>
- </section>
- </section>
-
-</chapter>